/**
  * Author: Mei
  * Date: 2021-01-06 15:05
  * Description: 
  *
  */
#include "../head.h"

#define HAS_MEMBER(member) \
template<typename T, typename...Args>\
struct has_member_##member{\
private:\
    template <typename U>\
    static auto Check(int) -> decltype(declval<U>().member(declval<Args>()...), true_type());\
    template <typename U>\
    static false_type Check(...);\
public:\
    enum {value = is_same<decltype(Check<T>(0)), true_type>::value};\
};\


HAS_MEMBER(Foo);

HAS_MEMBER(Before);

HAS_MEMBER(After);

class NonCopyable {
protected:
    NonCopyable() = default;

    ~NonCopyable() = default;

    NonCopyable(const NonCopyable &) = delete; //禁用复制构造
    NonCopyable &operator=(const NonCopyable &) = delete; //禁用赋值构造
};

/**
 * std::declval是c++11新标准中出现的函数模板，没有函数体（只有声明，没有实现），无法被调用，
一般用于与decltype，sizeof等关键字配合来进行类型推导、占用内存空间计算等。
 * 返回某个类型T的右值引用，不管该类型是否有默认构造函数或者该类型是否可以创建对象。
 * 返回某个类型T的右值引用 这个动作是在编译时完成的，所以很多人把std::declval也称为编译时工具。
 */
template<typename Func, typename ...Args>
struct Aspect : NonCopyable {
    Aspect(Func &&f) : m_func(forward<Func>(f)) {
    }

    template<typename T>
    typename enable_if<has_member_Before<T, Args...>::value && has_member_After<T, Args...>::value>::type
    Invoke(Args &&...args, T &&aspect) {
        aspect.Before(forward<Args>(args)...);
        m_func(forward<Args>(args)...);
        aspect.After(forward<Args>(args)...);
    }
    template<typename T>
    typename enable_if<has_member_Before<T, Args...>::value && !has_member_After<T, Args...>::value>::type
    Invoke(Args &&...args, T &&aspect) {
        aspect.Before(forward<Args>(args)...);
        m_func(forward<Args>(args)...);
    }

    template<typename Head, typename ...Tail>
    void Invoke(Args &&...args, Head &&headAspect, Tail &&...tailAspect) {
        headAspect.Before(forward<Args>(args)...);
        Invoke(forward<Args>(args)..., forward<Tail>(tailAspect)...);
        headAspect.After(forward<Args>(args)...);
    };

private:
    Func m_func;
};

template<typename T>
using identity_t = T;

template<typename ...AP, typename ...Args, typename Func>
void Invoke(Func &&f, Args &&...args) {
    Aspect<Func, Args...> asp(forward<Func>(f));
    asp.Invoke(forward<Args>(args)..., identity_t<AP>()...);
};

//测试
struct AA {
    void Before(int i) {
        cout << "Before form AA: " << i << endl;
    }

    void After(int i) {
        cout << "After form AA: " << i << endl;
    }
};

struct BB {
    void Before(int i) {
        cout << "Before form BB: " << i << endl;
    }

    void After(int i) {
        cout << "After form BB: " << i << endl;
    }
};

struct CC {
    void Before(int i) {
        cout << "Before form CC: " << i << endl;
    }

    void aAfter(int i) {
        cout << "After form CC: " << i << endl;
    }
};

void HT(int a) {
    cout << "real HT function: " << a << endl;
}

//时间类
struct TimeElapsedAspect {
    void Before(int i) {

    }

    void After(int i) {
        cout << "time elpsed: " << endl;
    }

private:
    double m_lastTime;
};

struct LoggingAspect {
    void Before(int i) {
        cout << "entering" << endl;
    }

    void aAfter(int i) {
        cout << "leaving" << endl;
    }
};

void TestAop() {
    Invoke<AA, BB, CC>(function<void(int)>(bind(&HT, placeholders::_1)), 1);
}

int main() {
    TestAop();

    return 0;
}